package priv.dajie.tzzq.bot.buff;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.omg.PortableServer.THREAD_POLICY_ID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import priv.dajie.tzzq.bot.Bot;
import priv.dajie.tzzq.common.ApplicationContextUnit;
import priv.dajie.tzzq.model.QualityName;
import priv.dajie.tzzq.model.SellType;
import priv.dajie.tzzq.service.PlatformService;
import priv.dajie.tzzq.spider.model.ItemInfo;
import priv.dajie.tzzq.bot.exception.*;
import priv.dajie.tzzq.bot.model.*;
import priv.dajie.tzzq.common.Tools;

import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class BuffBot implements Bot {

    private BuffUser buffUser;
    private PlatformService buffService = (PlatformService) ApplicationContextUnit.getInstance().getBean("buffService");
    private Map<String, TradeState> stateMap;
    private Logger logger = LogManager.getLogger(this.getClass());

    private final Pattern deliverPattern = Pattern.compile("sellingToDeliver\\((.*)\\).init");
    private final Pattern idPattern = Pattern.compile("[0-9]{6}T[0-9]{10}");

    {
        stateMap = new HashMap<>();
        stateMap.put("供应成功", TradeState.SUCCESS);
        stateMap.put("出售成功", TradeState.SUCCESS);
        stateMap.put("等待发货", TradeState.WAIT);
        stateMap.put("正在发货中", TradeState.WAIT);
    }

    public BuffUser getBuffUser() {
        return buffUser;
    }

    public BuffBot(BuffUser buffUser) {
        this.buffUser = buffUser;
        try {
            if (!(buffUser.isLogin() && buffUser.isVerify())) {
                throw new NeedLoginVerifyException("必须完成登陆和短信验证");
            }
        } catch (NetworkException e) {
            e.printStackTrace();
        }
    }

    @Override
    public PackItems getPack() {
        URIBuilder uriBuilder = null;
        HttpGet httpGet = null;
        int page = 1;
        int pageSize = 150;
        PackItems packItems = new PackItems();
        try {
            // 创建背包获取链接
            uriBuilder = new URIBuilder("https://buff.163.com/api/market/backpack");
            List<NameValuePair> data = new ArrayList<>();
            data.add(new BasicNameValuePair("game", "dota2"));
            data.add(new BasicNameValuePair("page_num", Integer.toString(page)));
            data.add(new BasicNameValuePair("page_size", pageSize+""));
            uriBuilder.setParameters(data);
            httpGet = new HttpGet(uriBuilder.build());
            // 获取背包数据
            String htmlText = buffUser.open(httpGet);
            // 解析背包数据，json分为两部分 1.goods_infos 包含商品信息 2.items 包含取回id
            JSONObject dataJson = JSON.parseObject(htmlText).getJSONObject("data");
            JSONObject goodsInfos = dataJson.getJSONObject("goods_infos");
            JSONArray items = dataJson.getJSONArray("items");
            // 遍历获取每个物品的信息
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = items.getJSONObject(i);
                String id = item.getString("id");
                String goodsId = item.getJSONObject("asset_info").getString("goods_id");
                //商品信息MAP
                JSONObject info = goodsInfos.getJSONObject(goodsId);
                String steamName = info.getString("market_hash_name");
                String name = info.getString("name");
                // 把背包物品信息放入List
                packItems.add(new PackItem(Tools.getQualityName(name), steamName, id));
            }
            return packItems;
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new NetworkException("URL解释异常 :" + e.getMessage());
        }
    }

    public BuffSteamPackItems getBuffSteamPackItems() {
        int page = 1;
        int max = 1;
        BuffSteamPackItems buffSteamPackItems = new BuffSteamPackItems();
        do {
            System.out.println(page);
            HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/steam_inventory?game=dota2&force=0&page_num=" + page + "&page_size=160&search=&state=tradable");
            String jsonStr = buffUser.open(httpGet);
            JSONObject json = JSON.parseObject(jsonStr);
            if (!json.getString("code").equals("OK")) {
                throw new NetworkException(json.getString("msg"));
            }
            JSONArray items = json.getJSONObject("data").getJSONArray("items");
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = items.getJSONObject(i);
                String steamName = item.getString("market_hash_name");
                String assetid = item.getString("assetid");
                String classid = item.getString("classid");
                String goodsid = item.getString("goods_id");
                String instanceid = item.getString("instanceid");
                String contextid = item.getString("contextid");
                Integer progress = item.getInteger("progress");
                BigDecimal price = item.getBigDecimal("sell_order_price");
                int progress2 = progress != null ? progress : -1;
                int state = item.getInteger("state");
                buffSteamPackItems.add(new BuffSteamPackItem(steamName, assetid, classid, goodsid, instanceid, contextid, progress2, state, price));
            }
            max = json.getJSONObject("data").getInteger("total_page");
            page++;
        } while (page <= max);
        return buffSteamPackItems;
    }

    @Override
    public HistoryPrices getHistoryPrice(String goodsID) {
        return getHistoryPrice(goodsID, 7);
    }

    @Override
    public HistoryPrices getHistoryPrice(String goodsId, int day) {
        HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/goods/price_history/buff?game=dota2&currency=CNY&days=30&goods_id=" + goodsId);
        String html = buffUser.open(httpGet);
        JSONObject json = JSON.parseObject(html);
        Date now = new Date();
//        double sumPrice = 0;
//        int num = 0;
        HistoryPrices historyPriceList = new HistoryPrices();
        //判断网页是否返回正确数据
        if (json.getString("code").equals("OK")) {
            JSONArray arr = json.getJSONObject("data").getJSONArray("price_history");
            for (int i = arr.size() - 1; i >= 0; i--) {
                JSONArray history = arr.getJSONArray(i);
                Date historyTime = new Date(history.getLong(0));
                int days = (int) ((now.getTime() - historyTime.getTime()) / (1000 * 60 * 60 * 24));
                // 判断获取的最大历史日期
                if (days >= day)
                {
                    break;
                }
//                num++;
//                sumPrice += history.getDouble(1);
                historyPriceList.add(new HistoryPrice(historyTime, history.getBigDecimal(1)));
            }
            return historyPriceList;
        }
        throw new NetworkException("网页没有返回正确信息");
    }


    @Override
    public BuyState buy(SellItem sellItem) {
        // 支付宝支付为(PayMethod.FAST)万能支付
        PayMethod payMethod = PayMethod.FAST;
        // 如果可以使用所有支付方式，则优先使用余额较多的支付方式
        if(sellItem.getPayMethod() == PayMethod.OTHER){
            try {
                BuffAsset buffAsset = getAsset();
                payMethod = buffAsset.getEpay() >= buffAsset.getAlipay()?PayMethod.OTHER:PayMethod.FAST;
            }catch (Exception e){
                logger.error("获取buff余额失败:"+e);
            }
        }

        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/goods/buy");
        httpPost.setHeaders(buffUser.getBuffHeaders());
        JSONObject jsonData = new JSONObject();
        jsonData.put("allow_tradable_cooldown", "0");
        jsonData.put("game", "dota2");
        jsonData.put("pay_method", payMethod.toString());
        // 待修改为物品对应的id
        jsonData.put("goods_id", "11502");
        jsonData.put("price", sellItem.getPrice() + "");
        jsonData.put("sell_order_id", sellItem.getId());
        jsonData.put("token", "");
//        System.out.println(jsonData);
        StringEntity entity = new StringEntity(jsonData.toString(), "UTF-8");
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        String html = buffUser.open(httpPost); // 提交request请求，并获取返回内容
//        System.out.println(html);
        JSONObject json = JSON.parseObject(html);
//        System.out.println(json);
        String code = json.getString("code");
        switch (code) {
            case "OK":
                return BuyState.SUCCESS;
            case "SellOrder Has Change":
                return BuyState.CHANGE;
            case "SellOrder Has Successed":
                return BuyState.NOT_FOUND;
            default:
                logger.error(json);
                break;
        }
        return BuyState.OTHER;
    }

    @Override
    public SellingMap getSelfSell(){
        return getSell(SellType.SELF_SELL);
    }

    @Override
    public SellingMap getOnSell(){
        return getSell(SellType.ON_SELL);
    }

    private SellingMap getSell(SellType sellType){
        SellingMap sellingMap = new SellingMap();
        HttpGet httpGet = new HttpGet("https://buff.163.com/market/sell_order/on_sale?game=dota2&mode="+sellType.getBuffNum());
//        System.out.println(httpGet);
        String html = buffUser.open(httpGet);
        Document document = Jsoup.parse(html);
        Element ul = document.selectFirst("ul.card_dota2");
        if(ul == null){
            return sellingMap;
        }
        Elements items = ul.select("li");
        for (Element item : items) {
            String goodsid = item.attr("data-goodsid");
            String orderid = item.attr("data-orderid");
            BigDecimal price = new BigDecimal(item.attr("data-price"));
            sellingMap.put(orderid, new SellingItem(goodsid, orderid, price));
        }
        return sellingMap;

    }

    @Deprecated
    public BuffSellingItems getSelfSellItems() { // 获取自售中的商品
        BuffSellingItems buffSteamPackItems = new BuffSellingItems();
        HttpGet httpGet = new HttpGet("https://buff.163.com/market/sell_order/on_sale?mode=2,5&game=dota2");
        String html = buffUser.open(httpGet);
        Document document = Jsoup.parse(html);
        Element ul = document.selectFirst("ul.card_dota2");
        Elements items = ul.select("li");
        for (Element item : items) {
            String goodsid = item.attr("data-goodsid");
            String orderid = item.attr("data-orderid");
            BigDecimal price = new BigDecimal(item.attr("data-price"));
            String steamName = buffService.getInfoById(goodsid).getSteamName();
            Element a = item.selectFirst("a.item-detail-img");
            String classid = a.attr("data-classid");
            String instanceid = a.attr("data-instanceid");
            String assetid = a.attr("data-assetid");
            String contextid = a.attr("data-contextid");
            buffSteamPackItems.add(new BuffSellingItem(steamName, orderid, assetid, classid, instanceid, contextid, goodsid, price));
        }
        return buffSteamPackItems;
    }

    public void selfSell(BuffSteamPackItem buffSteamPackItem, BigDecimal price) throws SellException {
        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/sell_order/create/manual");
        // 设置JSON
        JSONObject jsonData = new JSONObject();
        JSONArray assets = new JSONArray();
        JSONObject item = new JSONObject();
        item.put("assetid", buffSteamPackItem.getAssetid());
        item.put("classid", buffSteamPackItem.getClassid());
        item.put("contextid", "2");
        item.put("game", "dota2");
        item.put("goods_id", buffSteamPackItem.getGoodsid());
        item.put("instanceid", buffSteamPackItem.getInstanceid());
        item.put("market_hash_name", buffSteamPackItem.getSteamName());
        item.put("price", price + "");
        assets.add(item);
        jsonData.put("assets", assets);
        jsonData.put("game", "dota2");
        httpPost.setEntity(new StringEntity(jsonData.toString(), "utf-8"));
        httpPost.setHeaders(buffUser.getBuffHeaders());
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSON.parseObject(jsonStr);
        JSONObject data = json.getJSONObject("data");
        if (!(json.getString("code").equals("OK") && data.getString(buffSteamPackItem.getAssetid()).equals("OK"))) {
            throw new SellException(json.getString("msg"));
        }
    }

    public boolean changePrice(SellingItem buffSellingItem) throws SellException {
        SellingItem[] buffSellingItems = new SellingItem[1];
        buffSellingItems[0] = buffSellingItem;
        return changePrice(buffSellingItems).get(buffSellingItem.getSellID());
    }

    @Override
    public ChangePriceResults changePrice(List<SellingItem> sellingItems) throws SellException {
        SellingItem[] buffSellingItemArr = new SellingItem[sellingItems.size()];
        buffSellingItemArr = sellingItems.toArray(buffSellingItemArr);
        return changePrice(buffSellingItemArr);
    }

    public ChangePriceResults changePrice(SellingItem[] sellingItems) throws SellException { // 修改价格 , 2019.5.7寄售待测试
        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/sell_order/change");
        // 设置请求参数
        JSONObject jsonData = new JSONObject();
        jsonData.put("game", "dota2");
        JSONArray items = new JSONArray();
        for(SellingItem sellingItem : sellingItems) {
            JSONObject item = new JSONObject();
            item.put("desc", "");
            item.put("goods_id", sellingItem.getGoodsID());
            item.put("price", sellingItem.getPrice() + "");
            item.put("sell_order_id", sellingItem.getSellID());
            items.add(item);
        }
        jsonData.put("sell_orders", items);
        httpPost.setEntity(new StringEntity(jsonData.toString(), "utf-8"));
        httpPost.setHeaders(buffUser.getBuffHeaders());
        // 发送请求
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSONObject.parseObject(jsonStr);
        if (!json.getString("code").equals("OK")) {
            throw new SellException("价格修改失败：" + json.getString("error"));
        }
        // 解析更改价格的返回结果
        ChangePriceResults changePriceResults = new ChangePriceResults();
        JSONObject result = json.getJSONObject("data");
        for(SellingItem buffSellingItem : sellingItems){
            String orderID = buffSellingItem.getSellID();
            Boolean success = result.getString(orderID).equals("OK");
            if (!success){
                logger.error("更改价格时出现异常："+json);
            }
            changePriceResults.put(orderID, success);
        }
        return changePriceResults;
    }

    public BigDecimal fee(BigDecimal price) { // 获取手续费
        HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/batch/fee?game=dota2&prices=" + price);
        String jsonStr = buffUser.open(httpGet);
        JSONObject json = JSONObject.parseObject(jsonStr);
        if (!json.getString("code").equals("OK")) {
            throw new NetworkException("手续费获取失败：" + json.getString("msg"));
        }
        return json.getJSONObject("data").getBigDecimal("total_fee");
    }

    public void unSelfSell(BuffSellingItem buffSellingItem) throws SellException { // 自售商品下架
        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/sell_order/cancel");
        JSONObject jsonData = new JSONObject();
        JSONArray items = new JSONArray();
        items.add(buffSellingItem.getOrderid());
        jsonData.put("sell_orders", items);
        jsonData.put("game", "dota2");
        httpPost.setHeaders(buffUser.getBuffHeaders());
        httpPost.setEntity(new StringEntity(jsonData.toString(), "utf-8"));
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSONObject.parseObject(jsonStr);
        System.out.println(json);
        if (!json.getString("code").equals("OK")) {
            throw new SellException("自售下架失败：" + json.getString("error"));
        }
    }

    public List<SellingItem> getNeedToDeliverItems(){
        List<SellingItem> deliverItems = new ArrayList<>();
        HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/sell_order/to_deliver?appid=570");
        String jsonStr = buffUser.open(httpGet);
        JSONObject json = JSON.parseObject(jsonStr);
        if (!"OK".equals(json.getString("code"))){
            throw new DataException("返回数据异常，获取待发货商品失败："+json);
        }
        JSONObject data = json.getJSONObject("data");
        JSONArray items = data.getJSONArray("items");
        if (items == null || items.size()==0){
            return deliverItems;
        }
        for(int i=0;i<items.size();i++){
            JSONObject item = items.getJSONObject(i);
            String id = item.getString("id");
            String goodsID = item.getString("goods_id");
            BigDecimal price = item.getBigDecimal("price");
            deliverItems.add(new SellingItem(goodsID, id, price));
        }
        return deliverItems;
    }

    @Deprecated
    public List<BuffSellingItem> getNeedDelverItems() {
        HttpGet httpGet = new HttpGet("https://buff.163.com/market/sell_order/to_deliver?game=dota2");
        String html = buffUser.open(httpGet);
        Matcher matcher = deliverPattern.matcher(html);
        List<BuffSellingItem> buffSellingItems = new ArrayList<>();
        // 判断是否有待发货信息
        if (matcher.find()) {
            String text = matcher.group(1);
            Matcher idMatcher = idPattern.matcher(text);
            // 用于存放id
            List<String> ids = new ArrayList<>();
            // 用于存放get请求的id参数
            StringBuilder idStringBuffer = new StringBuilder();
            // 利用正则匹配ID
            while (idMatcher.find()) {
                String id = idMatcher.group(0);
                ids.add(id);
                idStringBuffer.append(id).append(",");
            }
            // 去除尾部逗号
            idStringBuffer.deleteCharAt(idStringBuffer.length() - 1);
            String jsonStr = buffUser.open(new HttpGet("https://buff.163.com/market/sell_order/to_deliver/batch?game=dota2&bill_orders=" + idStringBuffer));
            JSONObject json = JSON.parseObject(jsonStr);
            if (!"OK".equals(json.getString("code"))) // 判断是否正确返回
            {
                throw new NetworkException(json.getString("msg"));
            }
            html = json.getString("data"); // 获取json返回的html数据
            Document document = Jsoup.parse("<table><tbody>" + html + "</tbody></table>");
            Elements items = document.select("tr.deliver-order");
            for (Element item : items) {
                Element picdiv = item.selectFirst("div.pic-cont");
                String orderid = picdiv.attr("data-orderid");
                String classid = picdiv.attr("data-classid");
                String instanceid = picdiv.attr("data-instanceid");
                String assetid = picdiv.attr("data-assetid");
                String contextid = picdiv.attr("data-contextid");
                String priceStr = item.selectFirst("strong.f_Strong").text().replace("￥", "");
                String name = item.selectFirst("h3").text();
                BigDecimal price = new BigDecimal(priceStr);
                ItemInfo itemInfo = buffService.getInfoByQualityName(Tools.getQualityName(name));
                String steamName = itemInfo != null ? itemInfo.getSteamName() : "";
                BuffSellingItem buffSellingItem = new BuffSellingItem(steamName, orderid, assetid, classid, instanceid, contextid, "", price);
                buffSellingItems.add(buffSellingItem);
            }
        }
        return buffSellingItems;
    }

    public List<SellHistoryItem> getSellHistoryItems() { // 已完成 2019.5.12
        List<SellHistoryItem> sellHistoryItems = new ArrayList<>();
        int pageNum = 1;
        int maxPage = 1;
        int error = 0;
        do{
            HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/sell_order/history?game=dota2&page_size=30&page_num="+pageNum);
            String jsonStr = buffUser.open(httpGet);
            JSONObject json = JSON.parseObject(jsonStr);
            if(!"OK".equals(json.getString("code"))){
                if(error++>3) {
                    throw new DataException("获取出售记录时返回数据有误："+json);
                }
                continue;
            }
            JSONObject data = json.getJSONObject("data");
            maxPage = data.getInteger("total_page");
            JSONArray items = data.getJSONArray("items");
            JSONObject infos = data.getJSONObject("goods_infos");
            for(int i=0;i<items.size();i++){
                JSONObject item = items.getJSONObject(i);
                String goodsID = item.getString("goods_id");
                BigDecimal price = item.getBigDecimal("price");
                String state = item.getString("state");
                String id = item.getString("id");
                Date date = new Date(item.getLong("created_at")*1000L);
                TradeState tradeState;
                switch (state){
                    case "SUCCESS":
                        tradeState = TradeState.SUCCESS;
                        break;
                    case "FAIL":
                        tradeState = TradeState.FAIL;
                        break;
                    case "DELIVERING":
                    case "TO_DELIVER":
                        tradeState = TradeState.WAIT;
                        break;
                    default:
                        tradeState = TradeState.OTHER;
                        logger.error("获取buff交易记录发现未知状态："+state);
                }
                String steamName = infos.getJSONObject(goodsID).getString("market_hash_name");
                sellHistoryItems.add(new SellHistoryItem(steamName, id, price, date, tradeState));
            }
            pageNum++;
        }while (pageNum<maxPage);
        return sellHistoryItems;
    }

    @Override
    public TrackStateInfo[] tracker(String[] ids){
        HttpGet httpGet = createTrackerUrl(ids);
        String jsonStr = buffUser.open(httpGet);
        JSONObject json = JSON.parseObject(jsonStr);
        if(!"OK".equals(json.getString("code"))){
            throw new DataException("跟踪报价时返回内容错误："+json);
        }
        JSONArray datas = json.getJSONArray("data");
        TrackStateInfo[] trackStateInfos = new TrackStateInfo[datas.size()];
        for (int i=0; i<datas.size(); i++){
            JSONObject data = datas.getJSONObject(i);
            int state = data.getInteger("state");
            String tradeId = null;
            TrackState trackState;
            String id = data.getString("id");
            switch (state){
                case 0:
                    trackState = TrackState.SENDING;
                    break;
                case 1:
                    trackState = TrackState.SENDED;
                    tradeId = data.getString("tradeofferid");
                    break;
                case 2:
                    trackState = TrackState.SUCCESS;
                    break;
                case 3:
                    trackState = TrackState.FAIL;
                    break;
                default:
                    trackState = TrackState.OTHER;
                    logger.error("未知跟踪状态 "+state+":"+data.getString("text"));
            }
            trackStateInfos[i] = new TrackStateInfo(id, trackState, tradeId);
        }
        return trackStateInfos;
    }

    @Override
    public String[] takeBack(List<PackItem> packItems){
        if (packItems.size() > 5) {
            throw new TakeBackException("取回数量不能大于5");
        }
        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/backpack/withdraw");
        httpPost.setHeaders(buffUser.getBuffHeaders());
        JSONObject data = new JSONObject();
        data.put("game", "dota2");
        JSONArray ids = new JSONArray();
        for (PackItem packItem : packItems) {
            ids.add(packItem.getId());
        }
        data.put("backpack_ids", ids);
        StringEntity entity = new StringEntity(data.toString(), "UTF-8");
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSON.parseObject(jsonStr);
        if (!json.getString("code").equals("OK")) {
            throw new TakeBackException(json.toString());
        }
        JSONArray datas = json.getJSONArray("data");
        String[] IDs = new String[datas.size()];
        for (int i = 0; i < datas.size(); i++) {
            String id = datas.getJSONObject(i).getString("id");
            JSONArray items = datas.getJSONObject(i).getJSONArray("items_to_trade");
            IDs[i] = id;
        }
        return IDs;
    }

    @Override
    public String[] autoTakeBack(List<PackItem> packItems) {
      String[] IDs = takeBack(packItems);
        return autoTracker(IDs);
    }

    private HttpGet createTrackerUrl(String[] ids){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < ids.length; i++) {
            stringBuilder.append(ids[i]);
            if (i != ids.length - 1) {
                stringBuilder.append(",");
            }
        }
        return new HttpGet("https://buff.163.com/api/market/steam_trade/batch/info?bot_trades=" + stringBuilder.toString());
    }

    private String[] autoTracker(String[] ids) {
        HttpGet httpGet = createTrackerUrl(ids);
        int count = 0;
        while (true) {
            logger.info("等待buff机器人处理：第"+ ++count +"次");
            String jsonStr;
            try {
                jsonStr = buffUser.open(httpGet);
            }catch (NetworkException e){
                logger.error(e);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                continue;
            }
            JSONObject json = JSON.parseObject(jsonStr);
            if (!json.getString("code").equals("OK")) {
                throw new TakeBackException(json.getString("error"));
            }
            JSONArray datas = json.getJSONArray("data");
            int complete = 0;
            int error = 0;
            for (int i = 0; i < datas.size(); i++) {
                int stateCode = datas.getJSONObject(i).getInteger("state");
                if ((stateCode == 1 && datas.getJSONObject(i).getString("tradeofferid") != null)) {
                    complete++;
                } else if(stateCode == 3){
                    complete++;
                    error++;
                }
            }
            if (complete == datas.size()) {
                String[] steamTradeItems = new String[datas.size()-error];
                for (int i = 0, n = 0; i < datas.size(); i++) {
                    if(datas.getJSONObject(i).getInteger("state") == 1) {
                        String id = datas.getJSONObject(i).getString("tradeofferid");
                        steamTradeItems[n] = id;
                        n++;
                    }
                }
                return steamTradeItems;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public String[] deliver(List<SellingItem> sellingItems) {
        HttpPost httpPost = new HttpPost("https://buff.163.com/api/market/bill_order/deliver");
        httpPost.setHeaders(buffUser.getBuffHeaders());
        JSONObject jsonData = new JSONObject();
        jsonData.put("game", "dota2");
        JSONArray jsonArray = new JSONArray();
        for (SellingItem item : sellingItems) {
            jsonArray.add(item.getSellID());
        }
        jsonData.put("bill_orders", jsonArray);
        StringEntity entity = new StringEntity(jsonData.toString(), "UTF-8");
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSON.parseObject(jsonStr);
        if (!json.getString("code").equals("OK")) {
            throw new TakeBackException(json.toString());
        }
        String trackID = json.getJSONObject("data").getString("id");
        String[] ids = new String[1];
        ids[0] = trackID;
        return autoTracker(ids);
    }

    @Deprecated
    public List<String> deliverTracker(String id) { // 待测试
        HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/steam_trade/batch/info?bot_trades=" + id + "&_=" + System.currentTimeMillis());
        List<String> tradeids = new ArrayList<>();
        int round = 0;
        while (true) {
            int num = 0;
            System.out.println("第" + ++round + "报价发送中..");
            String jsonStr = buffUser.open(httpGet);
            JSONObject json = JSON.parseObject(jsonStr);
            System.out.println(json);
            if (!json.getString("code").equals("OK")) {
                throw new NetworkException(json.getString("msg"));
            }
            JSONArray datas = json.getJSONArray("data");
            int[] completeNum = new int[datas.size()];
            for (int i = 0; i < datas.size(); i++) {
                JSONObject data = datas.getJSONObject(i);
                int state = data.getInteger("state");
                String tradeid = data.getString("tradeofferid");
                // 判断该data是否已经处理完毕
                if (completeNum[i] == 0) {
                    if (state == 1 && tradeid != null) {
                        completeNum[i] = 1;
                        tradeids.add(tradeid);
                        num++;
                    } else if (state == 3) {
                        completeNum[i] = 3;
                        num++;
                    }
                }
            }
            // 判断是否已经全部处理完毕
            if (num == datas.size()) {
                break;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return tradeids;
    }

    @Override
    public List<SellItem> getSellItemsBySteamName(String steamName) {
        return getSellItems(steamName, NameType.STEAM_NAME);
    }

    @Override
    public List<SellItem> getSellItemsByID(String id) {
        return getSellItems(id, NameType.ID);
    }

    @Override
    // 获取商品出售列表
    public List<SellItem> getSellItems(String name, NameType nameType) {
        List<SellItem> sellItems = new ArrayList<>();
        String id;
        if (nameType == NameType.STEAM_NAME) {
            ItemInfo itemInfo = buffService.getInfoBySteamName(name);
            if (itemInfo == null) {
                return sellItems;
            }
            id = itemInfo.getId();
        } else {
            id = name;
        }
        String html = buffUser.open(new HttpGet("https://buff.163.com/api/market/goods/sell_order?game=dota2&goods_id=" + id + "&page_num=1&sort_by=default&mode=&allow_tradable_cooldown=1"));
        JSONObject json = JSON.parseObject(html);
        JSONObject data = json.getJSONObject("data");
        if (data == null) {
            return sellItems;
        }
        JSONArray items = data.getJSONArray("items");
        for (int i = 0; i < items.size(); i++) {
            JSONObject item = items.getJSONObject(i);
            String itemid = item.getString("id");
            BigDecimal price = item.getBigDecimal("price");
            PayMethod payMethod = item.getJSONArray("supported_pay_methods").size()>1?PayMethod.OTHER:PayMethod.FAST; // 多于一个支付方式使用银行卡，等于一个使用支付宝
            sellItems.add(new SellItem(itemid, price, payMethod));
        }
        return sellItems;
    }

    @Override
    public List<BuyItem> getBuyItemsBySteamName(String steamName) {
        return getBuyItems(steamName, NameType.STEAM_NAME);
    }

    public List<BuyItem> getBuyItemsByID(String id) {
        return getBuyItems(id, NameType.ID);
    }

    // 获取商品求购列表
    public List<BuyItem> getBuyItems(String name, NameType nameType) {
        List<BuyItem> buyItems = new ArrayList<>();
        String id;
        if (nameType == NameType.STEAM_NAME) {
            ItemInfo itemInfo = buffService.getInfoBySteamName(name);
            if (itemInfo == null) {
                return buyItems;
            }
            id = itemInfo.getId();
        } else {
            id = name;
        }
        String html = buffUser.open(new HttpGet("https://buff.163.com/api/market/goods/buy_order?game=dota2&goods_id=" + id + "&page_num=1"));
        JSONObject json = JSON.parseObject(html);
        JSONObject data = json.getJSONObject("data");
        if (data == null) {
            return buyItems;
        }
        JSONArray items = data.getJSONArray("items");
        for (int i = 0; i < items.size(); i++) {
            JSONObject item = items.getJSONObject(i);
            int num = item.getInteger("num");
            BigDecimal price = item.getBigDecimal("price");
            String itemid = item.getString("id");
            buyItems.add(new BuyItem(itemid, price, num));
        }
        return buyItems;
    }

    @Override
    public BuyHistoryItems getBuyHistory(int pageMax, String id, long time) { // 获取购买历史
        BuyHistoryItems buyHistoryItems = new BuyHistoryItems();
        int page = 1;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = new Date();
        r:
        while (page <= pageMax) {
            HttpGet httpGet = new HttpGet("https://buff.163.com/market/buy_order/history?game=dota2&page_num=" + page);
            String html;
            try {
                html = buffUser.open(httpGet);
            }catch (NetworkException e){
                try {
                    Thread.sleep(300);
                    logger.error(e);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                continue ;
            }
            Document document = Jsoup.parse(html);
            Element table = document.selectFirst("tbody.list_tb_dota2");
            Elements items = table.select("tr");
            for (Element item : items) {
                String buyID = item.attr("id").replace("bill_order_","");
                String goodsIDHref = item.selectFirst("a[href^=/market]").attr("href");
                String goodsID = goodsIDHref.replace("/market/goods?goods_id=", "");
                QualityName qualityName = Tools.getQualityName(item.selectFirst("span.textOne").text());
                String stateStr = item.selectFirst("td.t_Left.deliver-expire.td_status").selectFirst("p").text();
                TradeState tradeState = Tools.buffBuyStateParse(stateStr);
                String dateStr = item.select("td.c_Gray.t_Left").get(0).text();
                Date date = null;
                try {
                    date = simpleDateFormat.parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                // 如果时间>搜索时间则退出循环
                if (time != -1 && date != null && now.getTime() - date.getTime() > time && page > 25) {
                    break r;
                }
                buyHistoryItems.add(new BuyHistoryItem(qualityName, goodsID, buyID, tradeState, date));
                if (id != null && id.equals(buyID)) {
                    break r;
                }
            }
            page++;
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                logger.error(httpGet);
                e.printStackTrace();
            }
        }
        return buyHistoryItems;
    }

    @Override
    public BuyHistoryItems getBuyHistory(int pageMax) {
        return getBuyHistory(pageMax, null, -1);
    }

    @Override
    public BuyHistoryItems getBuyHistoryByTime(long time) {
        return getBuyHistory(200, null, time);
    }

    public BuyHistoryItems getBuyHistory(String id) {
        return getBuyHistory(200, id, -1);
    }

    public BuyResult buyPro(SellItem sellItem, String goodsID) throws BuyException {
        BuyState buyState = buy(sellItem);
        if (buyState == BuyState.SUCCESS || buyState == BuyState.WAIT) {
            List<BuyHistoryItem> buyHistoryItems = getBuyHistory(1);
            for (BuyHistoryItem buyHistoryItem : buyHistoryItems) {
                if (buyHistoryItem.getGoodsID().equals(goodsID)) {
                    return new BuyResult(buyState, buyHistoryItem.getBuyID());
                }
            }
        } else {
            return new BuyResult(buyState, null);
        }
        throw new BuyException("查询购买记录失败");
    }

    private void getBuyHistoryInfo(int maxPage, Game game) throws Exception {
//        for(int page = 1;page <= maxPage;page++) {
//            HttpGet httpGet = new HttpGet("https://buff.163.com/market/buy_order/history?game=" + game.toString() + "&page_num=" + page);
//            String html = buffUser.open(httpGet);
//            Document document = Jsoup.parse(html);
//        }
    }

    public MinPrices getMinPrices(List<BuffSellingItem> buffSellingItems){

        BuffSellingItem[] buffSellingItemsArr = new BuffSellingItem[buffSellingItems.size()];
        return getMinPrices(buffSellingItems.toArray(buffSellingItemsArr));
    }

    public MinPrices getMinPrices(BuffSellingItem[] buffSellingItems){
        String url = "https://buff.163.com/market/sell_order/change_preview";
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonData = new JSONObject();
        jsonData.put("game", "dota2");
        JSONArray orders = new JSONArray();
        // 添加需要查询的商品数据
        for(BuffSellingItem buffSellingItem : buffSellingItems){
            JSONObject orderItem = new JSONObject();
            orderItem.put("goods_id", buffSellingItem.getGoodsid());
            orderItem.put("has_market_min_price", false);
            orderItem.put("income", "");
            orderItem.put("price", "");
            orderItem.put("sell_order_id", buffSellingItem.getOrderid());
            orders.add(orderItem);
        }
        jsonData.put("sell_orders", orders);
        httpPost.setEntity(new StringEntity(jsonData.toString(), "utf-8"));
        httpPost.setHeaders(buffUser.getBuffHeaders());
        // 提交post请求
        String jsonStr = buffUser.open(httpPost);
        JSONObject json = JSON.parseObject(jsonStr);
        if(!json.getString("code").equals("OK")){
            throw new DataException("获取最低价失败："+json);
        }
        String html = json.getString("data");
        Document document = Jsoup.parse(html);
        Elements items = document.select("tr[id^=sell_order_change_]");
        MinPrices minPrices = new MinPrices();
        for(int i = 0;i<items.size();i++){
            Element item = items.get(i);
            String id = item.attr("id");
            Matcher matcher = idPattern.matcher(id);
            if (matcher.find()){
                id = matcher.group(0);
            }
            Element priceEle = item.selectFirst("strong.f_Strong");
            String priceStr = priceEle.text().replace("￥", "");
            BigDecimal price = new BigDecimal(priceStr);
            minPrices.put(id, price);
        }
        return minPrices;
    }

    @Override
    public boolean isTrading(){
        HttpGet httpGet = new HttpGet("https://buff.163.com/api/market/steam_trade");
        String jsonStr;
        try {
            jsonStr = buffUser.open(httpGet);
        }catch (NetworkException e){
            logger.error(e);
            return true;
        }
        JSONObject json = JSON.parseObject(jsonStr);
        return json.getJSONArray("data").size()>0;
    }

    public BuffAsset getAsset(){
        return buffUser.getAsset();
    }

}
